package cn.glf.papersize.util;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;

import cn.glf.papersize.bean.CutCount;
import cn.glf.papersize.bean.CutMethod;
import cn.glf.papersize.bean.CutSolution;
import cn.glf.papersize.bean.Paper;

/**
 * Created by glf on 18-5-20.
 */

public class PageSizeUtil {

    public static final CutMethod CUT_METHOD_WIDTH_WIDTH = new CutMethod(1, "切法1-纸品宽度对应所需尺寸宽度");
    public static final CutMethod CUT_METHOD_WIDTH_HEIGHT = new CutMethod(2, "切法2-纸品宽度对应所需尺寸长度");

    public static final Paper ZHENG_GUI_PAPER = new Paper(
            new BigDecimal(1092), new BigDecimal(787), "正规", "zhenggui");

    public static final Paper DA_GUI_PAPER = new Paper(
            new BigDecimal(1194), new BigDecimal(889), "大规", "dagui");

    public static void main(String[] args) {
        Paper specifyPaper = new Paper(new BigDecimal(133), new BigDecimal(12));
        CutSolution cutSolution = chooseBestCutSolution(specifyPaper);
        System.out.println("最节省纸的切法为:");
        System.out.println(cutSolution);
        for(CutSolution detail : cutSolution.getDetails()){
            System.out.println("==============");
            System.out.println(detail);
        }
    }

    public static CutSolution chooseBestCutSolution(Paper specifyPaper){
        CutCount cutCountZhengGui1 = new CutCount();
        CutCount cutCountZhengGui2 = new CutCount();
        CutCount cutCountDaGui1 = new CutCount();
        CutCount cutCountDaGui2 = new CutCount();
        cut(
                specifyPaper,
                ZHENG_GUI_PAPER.getWidth(),
                ZHENG_GUI_PAPER.getHeight(),
                cutCountZhengGui1
        );
        cut(
                specifyPaper,
                ZHENG_GUI_PAPER.getHeight(),
                ZHENG_GUI_PAPER.getWidth(),
                cutCountZhengGui2
        );
        cut(
                specifyPaper,
                DA_GUI_PAPER.getWidth(),
                DA_GUI_PAPER.getHeight(),
                cutCountDaGui1
        );
        cut(
                specifyPaper,
                DA_GUI_PAPER.getHeight(),
                DA_GUI_PAPER.getWidth(),
                cutCountDaGui2
        );

        CutSolution solution1 = new CutSolution(specifyPaper, ZHENG_GUI_PAPER, CUT_METHOD_WIDTH_WIDTH, cutCountZhengGui1);
        CutSolution solution2 = new CutSolution(specifyPaper, ZHENG_GUI_PAPER, CUT_METHOD_WIDTH_HEIGHT, cutCountZhengGui2);
        CutSolution solution3 = new CutSolution(specifyPaper, DA_GUI_PAPER, CUT_METHOD_WIDTH_WIDTH, cutCountDaGui1);
        CutSolution solution4 = new CutSolution(specifyPaper, DA_GUI_PAPER, CUT_METHOD_WIDTH_HEIGHT, cutCountDaGui2);

        BigDecimal leftArea1 = solution1.getLeftArea();
        BigDecimal leftArea2 = solution2.getLeftArea();
        BigDecimal leftArea3 = solution3.getLeftArea();
        BigDecimal leftArea4 = solution4.getLeftArea();

        HashMap<BigDecimal, CutSolution> solutionHashMap = new HashMap<>();
        solutionHashMap.put(leftArea4, solution4);
        solutionHashMap.put(leftArea3, solution3);
        solutionHashMap.put(leftArea2, solution2);
        solutionHashMap.put(leftArea1, solution1);

        BigDecimal[] totals = new BigDecimal[]{leftArea1, leftArea2, leftArea3, leftArea4};
        Arrays.sort(totals);

        CutSolution min = solutionHashMap.get(totals[0]);
        List<CutSolution> list = new ArrayList();
        list.add(solution1);
        list.add(solution2);
        list.add(solution3);
        list.add(solution4);
        min.setDetails(list);

        return min;
    }

    /**
     * 获取包含子节点的总数量
     * @param cutCount
     * @return
     */
    public static BigDecimal getTotalCount(CutCount cutCount){
        BigDecimal total = BigDecimal.ZERO;
        if(cutCount != null){
            total = total
                    .add(cutCount.getTotalCount())
                    .add(getTotalCount(cutCount.getWidthChildren()))
                    .add(getTotalCount(cutCount.getHeightChildren()));
        }
        return total;
    }

    /**
     * 切割
     * @param specifyPaper
     * @param xAll
     * @param yAll
     * @param cutCount
     * @return
     */
    public static boolean cut(Paper specifyPaper, BigDecimal xAll, BigDecimal yAll, CutCount cutCount){
        BigDecimal xSpecify = specifyPaper.getWidth();
        BigDecimal ySpecify = specifyPaper.getHeight();

        if(xAll.compareTo(xSpecify) >= 0 && yAll.compareTo(ySpecify) >= 0){
            BigDecimal xCount = xAll.divide(xSpecify, 0, BigDecimal.ROUND_DOWN);
            BigDecimal yCount = yAll.divide(ySpecify, 0, BigDecimal.ROUND_DOWN);

            BigDecimal xUsed = xSpecify.multiply(xCount);
            BigDecimal yUsed = ySpecify.multiply(yCount);

            BigDecimal xLeft = xAll.subtract(xUsed);
            BigDecimal yLeft = yAll.subtract(yUsed);

//            System.out.println("================");
//            System.out.println(xCount.intValue());
//            System.out.println(yCount.intValue());
            cutCount.setWidthCount(xCount);
            cutCount.setHeightCount(yCount);
//            System.out.println("================");

            //x轴的剩余部分中，删除与y轴重叠的部分之后，x轴还可用的长度
            BigDecimal xAllNoRepeat = xUsed;
            //y轴的剩余部分中，删除与x轴重叠的部分之后，x轴还可用的长度
            BigDecimal yAllNoRepeat = yUsed;

            //x轴剩余的在旋转90度之后是否可以再切
            boolean xLeftCanCut = xLeft.compareTo(ySpecify) >= 0 && yAllNoRepeat.compareTo(xSpecify) >= 0;
            //y轴剩余的在旋转90度之后是否可以再切
            boolean yLeftCanCut = yLeft.compareTo(xSpecify) >= 0 && xAllNoRepeat.compareTo(ySpecify) >= 0;

            //如果x轴剩余的可以再切同时y轴剩余的也可以再切，那么舍弃掉各自剩余部分重合的部分
            if(xLeftCanCut && yLeftCanCut){
                BigDecimal xCanUse = xAll.subtract(xLeft);
                BigDecimal yCanUse = yAll.subtract(yLeft);

                CutCount xChildren = new CutCount();
                CutCount yChildren = new CutCount();
                cutCount.setWidthChildren(xChildren);
                cutCount.setHeightChildren(yChildren);

                cut(specifyPaper, yCanUse, xLeft, xChildren);
                cut(specifyPaper, yLeft, xCanUse, yChildren);
            }
            //如果只有x轴剩余的可以再切，那么x轴不能使用重合部分，在y轴方向可以使用全部
            else if(xLeftCanCut && !yLeftCanCut){
                CutCount xChildren = new CutCount();
                cutCount.setWidthChildren(xChildren);
                cut(specifyPaper, yAll, xLeft, xChildren);
            }
            //如果只有y轴剩余的可以再切，那么y轴不能使用重合部分，在x轴方向可以使用全部
            else if(!xLeftCanCut && yLeftCanCut){
                CutCount yChildren = new CutCount();
                cutCount.setHeightChildren(yChildren);
                cut(specifyPaper, yLeft, xAll, yChildren);
            }
            //如果都不可以切，那再分别判断加上重叠部分之后可不可以再切
            else{
                //x轴剩余的在旋转90度之后是否可以再切
                xLeftCanCut = xLeft.compareTo(ySpecify) >= 0 && yAll.compareTo(xSpecify) >= 0;
                //y轴剩余的在旋转90度之后是否可以再切
                yLeftCanCut = yLeft.compareTo(xSpecify) >= 0 && xAll.compareTo(ySpecify) >= 0;
                //如果都可以切，那谁切的多，让谁切
                if(xLeftCanCut && yLeftCanCut){
                    //x轴剩余部分旋转90度，可以切的数量
                    BigDecimal xLeftCount = yAll.divide(xSpecify, 0, BigDecimal.ROUND_DOWN);
                    //y轴剩余部分旋转90度，可以切的数量
                    BigDecimal yLeftCount = xAll.divide(ySpecify, 0, BigDecimal.ROUND_DOWN);
                    //x轴剩余部分可以切的更多,那只让x轴剩余部分来切
                    if(xLeftCount.compareTo(yLeftCount) >= 0){
                        CutCount xChildren = new CutCount();
                        cutCount.setWidthChildren(xChildren);
                        cut(specifyPaper, yAll, xLeft, xChildren);
                    }
                    //y轴剩余部分可以切的更多,那只让y轴剩余部分来切
                    else{
                        CutCount yChildren = new CutCount();
                        cut(specifyPaper, yLeft, xAll, yChildren);
                    }
                }
            }

            return true;
        }else{
            return false;
        }
    }



//    /**
//     * 算出指定的尺寸在指定规格的纸上，同时在指定方法下，可以切出多少张纸
//     * @param cutPaper
//     * @param needPaper
//     * @param cutMethod
//     * @return
//     */
//    public static CutCount getCutCount(Paper cutPaper, Paper needPaper, CutMethod cutMethod){
//        CutCount cutCount = new CutCount();
//        int widthCanCutCount = 0;
//        int heightCanCutCount = 0;
//        if(needPaper.getArea() != 0) {
//            if (CUT_METHOD_WIDTH_WIDTH.equals(cutMethod)) {
//                widthCanCutCount = new Double(cutPaper.getWidth() / needPaper.getWidth()).intValue();
//                heightCanCutCount = new Double(cutPaper.getHeight() / needPaper.getHeight()).intValue();
//            } else if (CUT_METHOD_WIDTH_HEIGHT.equals(cutMethod)) {
//                widthCanCutCount = new Double(cutPaper.getWidth() / needPaper.getHeight()).intValue();
//                heightCanCutCount = new Double(cutPaper.getHeight() / needPaper.getWidth()).intValue();
//            }
//        }
//        cutCount.setWidthCount(widthCanCutCount);
//        cutCount.setHeightCount(heightCanCutCount);
//        return cutCount;
//    }
//
//    /**
//     * 计算使用指定方法切割后余的纸的面积
//     * @param cutPaper
//     * @param needPaper
//     * @param cutMethod
//     * @return
//     */
//    public static double getCutLeftArea(Paper cutPaper, Paper needPaper, CutMethod cutMethod){
//        int canCutCount = getCutCount(cutPaper, needPaper, cutMethod).getTotalCount();
//        return cutPaper.getArea() - needPaper.getArea() * canCutCount;
//    }
//
//    /**
//     * 算出指定的尺寸在指定规格的纸上的最佳切割方法
//     * @param cutPaper
//     * @param needPaper
//     * @return
//     */
//    public static CutMethod getBestCutMethodForPaper(Paper cutPaper, Paper needPaper){
//        double widthWidthLeft = getCutLeftArea(cutPaper, needPaper, CUT_METHOD_WIDTH_WIDTH);
//        double widthHeightLeft = getCutLeftArea(cutPaper, needPaper, CUT_METHOD_WIDTH_HEIGHT);
//        if(widthWidthLeft <= widthHeightLeft){
//            return CUT_METHOD_WIDTH_WIDTH;
//        }else{
//            return CUT_METHOD_WIDTH_HEIGHT;
//        }
//    }
//
//    /**
//     * 计算使用那种规格的纸最后余的最少，浪费的最少
//     * @param needPaper
//     * @return
//     */
//    public static CutSolution getBestCutSolution(Paper needPaper){
//        CutMethod zhengGuiBestMethod = getBestCutMethodForPaper(ZHENG_GUI_PAPER, needPaper);
//        CutMethod daGuiBestMethod = getBestCutMethodForPaper(DA_GUI_PAPER, needPaper);
//
//        CutCount zhengGuiCutCount = getCutCount(ZHENG_GUI_PAPER, needPaper, zhengGuiBestMethod);
//        CutCount daGuiCutCount = getCutCount(DA_GUI_PAPER, needPaper, daGuiBestMethod);
//
//        double zhengGuiLeft = getCutLeftArea(ZHENG_GUI_PAPER, needPaper, zhengGuiBestMethod);
//        double daGuiLeft = getCutLeftArea(DA_GUI_PAPER, needPaper, daGuiBestMethod);
//
//        CutSolution cutSolution = new CutSolution(needPaper);
//        if(zhengGuiLeft <= daGuiLeft){
//            cutSolution.setCutPaper(ZHENG_GUI_PAPER);
//            cutSolution.setCutMethod(zhengGuiBestMethod);
//            cutSolution.setCutCount(zhengGuiCutCount);
//            cutSolution.setLeftArea(zhengGuiLeft);
//            cutSolution.setLeftAreaAsNeedPaperCount(1.0*zhengGuiLeft/(needPaper.getArea() == 0 ? 1 : needPaper.getArea()));
//        }else{
//            cutSolution.setCutPaper(DA_GUI_PAPER);
//            cutSolution.setCutMethod(daGuiBestMethod);
//            cutSolution.setCutCount(daGuiCutCount);
//            cutSolution.setLeftArea(daGuiLeft);
//            cutSolution.setLeftAreaAsNeedPaperCount(1.0*daGuiLeft/(needPaper.getArea() == 0 ? 1 : needPaper.getArea()));
//        }
//        return cutSolution;
//    }
//
//    /**
//     * 获取指定方法的切割方案
//     * @param needPaper
//     * @param cutPaper
//     * @param cutMethod
//     * @return
//     */
//    public static CutSolution getSpecifyCutSolution(Paper needPaper, Paper cutPaper, CutMethod cutMethod){
//        CutCount cutCount = getCutCount(cutPaper, needPaper, cutMethod);
//        double left = getCutLeftArea(cutPaper, needPaper, cutMethod);
//        CutSolution cutSolution = new CutSolution(needPaper);
//
//        cutSolution.setCutPaper(cutPaper);
//        cutSolution.setCutMethod(cutMethod);
//        cutSolution.setCutCount(cutCount);
//        cutSolution.setLeftArea(left);
//        cutSolution.setLeftAreaAsNeedPaperCount(1.0*left/(needPaper.getArea() == 0 ? 1 : needPaper.getArea()));
//
//        return cutSolution;
//    }
//
//    public static void main(String[] args) {
//        Paper a = null;
//
//        a = new Paper(13.12, 23.23);
//        System.out.println(getBestCutSolution(a));
//
//        a = new Paper(39.34, 39.56);
//        System.out.println(getBestCutSolution(a));
//
//    }
}
